package com.algorithms;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import twitter4j.Status;
import twitter4j.User;

public class DocumentSupport {

	private static Set<String> stopwords = null;

	private static Stemmer stemmer = null;

	public static void init(String language) {

		// TODO Factory pattern.
		if ("EN".equals(language))
			stemmer = new PorterStemmerEN();
		else
			stemmer = new PorterStemmerES();

		stopwords = new HashSet<String>();

		BufferedReader br;
		try {
			br = new BufferedReader(new FileReader("resources/stopwords_"
					+ language + ".txt"));

			String line;

			while ((line = br.readLine()) != null) {
				stopwords.add(line.trim());
			}

		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("no stopwords found.");
		}

	}

	/**
	 * this method will get the follows of the user and will generate 1 for each
	 * follow with all the statuses of that person.<BR>
	 * A document is represented as a list of words.
	 * 
	 * @param alreadyChecked
	 * 
	 * @param twitter
	 * @return
	 */
	public static List<Document> generateDocuments(Set<Integer> alreadyChecked) {

		List<Integer> follows = TwitterApi.getSeguidos();

		List<Document> documents = new ArrayList<Document>();

		int i = 1;
		// for each user
		for (Integer userId : follows) {

			// add it so we don´t recommend this user later
			alreadyChecked.add(userId);

			User u = TwitterApi.showUser(userId);

			// para debug TODO borrame dsps
			if (u != null) System.out.println(i++ + ") " + u.getScreenName());

			// get latest posts
			List<Status> status = TwitterApi.getUserStatus(userId);

			// create empty document
			Document document = new Document();

			// add all the cleaned tweets to the documents
			for (Status s : status)
				document.addAll(getCleanStatus(s.getText()));

			// add the document to the collection of documents.
			documents.add(document);
		}

		return documents;
	}

	/**
	 * this method creates a list of Documents. Every document is created by a
	 * different tweet of the user topTweets.
	 * 
	 * @param recommendedUsers
	 * 
	 * @param twitter
	 * @return
	 */
	public static List<Document> generateSuggestions(int page,
			Set<Integer> alreadyChecked, String user) {

		List<Document> suggestions = new ArrayList<Document>();

		List<Status> tweetList = null;

		/**
		 * doing this beacuse twitter api doesn't tell you how many favorites a
		 * user has. So if the result is empty check the next 10 pages. If all
		 * of them are empty we are assuming that there are no more tweets.
		 */
		int tries = 0;
		while (tries < 10) {

			tweetList = TwitterApi.getTopTweetsFavorites(page + tries, user);

			if (tweetList == null || tweetList.size() == 0)
				tries++;
			else
				break;
		}

		if (tweetList == null || tweetList.size() == 0) return null;

		// for each tweet of the user topTweet
		for (Status status : tweetList) {

			// get the user who made this post.
			int userId = status.getUser().getId();

			/*
			 * it might happen that a user has >1 tweets as a top tweet. So
			 * check in the set of all the users we have seen.
			 */
			if (alreadyChecked.contains(new Integer(userId))) continue;

			alreadyChecked.add(new Integer(userId));

			// create an empty document.
			Document document = new Document();
			document.setUser(status.getUser());

			// add all the tweets (previously cleaned) to the document
			for (Status s : TwitterApi.getUserStatus(userId))
				document.addAll(getCleanStatus(s.getText()));

			// add the document to the list of suggested documents.
			suggestions.add(document);
		}

		return suggestions;
	}

	/**
	 * gets all the cleaned words from a post and returns it as a ponderatedWord
	 * list.
	 * 
	 * @param message
	 * @return
	 */
	private static List<PonderatedWord> getCleanStatus(String message) {

		List<PonderatedWord> words = new ArrayList<PonderatedWord>();

		// for each word
		for (String word : message.split(" ")) {
			// clean it
			String aux = cleanWord(word);

			// if it's not null and not empty
			if (aux != null && !aux.equals(""))
			// create a ponderated word with this word and add it to the list.
				words.add(new PonderatedWord(aux, -1));
		}
		return words;
	}

	/**
	 * Cleans the word. I.e. applies the porter algorithm for stemming, puts the
	 * word to lower case, if the word has an @ it will remove it; if it has an
	 * # it removes the first character, and if it's a stopword it will remove
	 * the word. otherwise it will return the word stemmized and in lower case.
	 * 
	 * @param word
	 * @return
	 */
	private static String cleanWord(String word) {

		if (word == null) return null;

		word = word.trim();

		if (word.startsWith("#")) word = word.substring(1);

		if (word.startsWith("@")) return null;// word = word.substring(1);

		word = word.toLowerCase();

		try {
			word = stemmer.stem(word);
		} catch (IndexOutOfBoundsException e) {
			return null;
		}

		if (stopwords.contains(word)) return null;

		return word;
	}
}